# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: inkyu

import json
import logging
from collections import namedtuple

from http.cookies import SimpleCookie

from coin.base.timestamp import get_timestamp

UpbitRemainingReq = namedtuple('UpbitRemainingReq', ['min', 'sec'])


def _remaining_req_from_response(response, group='default'):
  remaining_req = response.headers.get('Remaining-Req', None)
  if remaining_req is None:
    logging.error('Remaining-Req field not found in http header!')
    return None

  parser = SimpleCookie()
  parser.load(remaining_req)
  if group:
    if parser['group'].value == 'tolerant':
      resp_dict = {
          'url': response.url,
          'headers': dict(response.headers),
          'status_code': response.status_code,
          'text': response.text,
      }
      logging.info('Meet tolerant group when handling rate limit info! response: \n %s',
                   json.dumps(resp_dict, indent=2, default=str))
      return None
    else:
      assert parser['group'].value == group, (parser['group'].value, group, parser)

  min_limit = int(parser['min'].value)
  sec_limit = int(parser['sec'].value)
  return UpbitRemainingReq(min=min_limit, sec=sec_limit)


class UpbitRateLimiter(object):
  def __init__(self, logger=None, verbose=True):
    self._default = UpbitRemainingReq(10, 10)
    self._order = UpbitRemainingReq(10, 10)
    self._next_ts_default = None
    self._next_ts_order = None
    self._logger = logger or logging.getLogger(__name__)
    self._verbose = verbose

  @property
  def default(self):
    return self._default

  @property
  def order(self):
    return self._order

  def default_available(self):
    if self._next_ts_order:
      timestamp = get_timestamp()
      if timestamp > self._next_ts_default:
        self._next_ts_default = None
      else:
        return False
    return True

  def order_available(self):
    if self._next_ts_order:
      timestamp = get_timestamp()
      if timestamp > self._next_ts_order:
        self._next_ts_order = None
      else:
        return False
    return True

  def update_default(self, response):
    remaining_req = _remaining_req_from_response(response, 'default')
    if remaining_req is None:
      return

    self._default = remaining_req
    # if self._verbose:
    #  self._logger.info('Default: %s', self._default)
    if self._default.min <= 3 or self._default.sec <= 1:
      self._next_ts_default = get_timestamp() + 1e9  # Rest for 1 sec

  def update_order(self, response):
    remaining_req = _remaining_req_from_response(response, 'order')
    if remaining_req is None:
      return

    self._order = remaining_req
    if self._verbose:
      self._logger.info('Order: %s', self._order)
    if self._order.min <= 3 or self._order.sec <= 1:
      self._next_ts_order = get_timestamp() + 1e9  # Rest for 1 sec
